package auto.common.service.impl;

import auto.common.entity.CaseInformationEntity;
import auto.common.enums.CollNameType;
import auto.common.enums.SheetNameType;
import auto.common.service.ParameterAssemblyService;
import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 将参数进行组装且构造为可用参数
 *
 * @author yangsen
 * @date 2025-10-20
 */
public class ParameterAssemblyServiceImpl implements ParameterAssemblyService {

    // 获取当前类的日志对象（推荐使用类名作为日志名）
    private static final Logger logger = LoggerFactory.getLogger(ParameterAssemblyServiceImpl.class);

    /**
     * 获取模板中的所有数据,且校验模板
     *
     * @param filePath 文件路径
     * @return 获取模板中数据集合信息
     */
    public CaseInformationEntity ReadTemplateExcel(String filePath) {
        //校验模板获取请求sheet页名称
        List<String> sheetnames = ReadTemplateExcelCheck(filePath);
        //1.从文件中读取案例信息Excel为ExcelReader
        ExcelReader reader = ExcelUtil.getReader(FileUtil.file(filePath), SheetNameType.CASEINFORMATION.getSheetName());
        //从流中读取Excel为ExcelReader（比如从ClassPath中读取Excel文件）
//        ExcelReader reader = ExcelUtil.getReader(ResourceUtil.getStream(filePath));
        List<Map<String, Object>> mapList = reader.readAll();
        //2.从文件中读取断言信息Excel为ExcelReader
        ExcelReader readerAssert = ExcelUtil.getReader(FileUtil.file(filePath), SheetNameType.ASSERTIONMESSAGE.getSheetName());
        List<Map<String, Object>> assertList = readerAssert.readAll();
        //3.从文件中读取请求信息Excel为ExcelReader
        ExcelReader readerRequest = ExcelUtil.getReader(FileUtil.file(filePath), SheetNameType.REQUESTINFORMATION.getSheetName());
        List<Map<String, Object>> requestList = readerRequest.readAll();
        //4.从请求中读取请求参数并存入map中
        HashMap<String, List<Map<String, Object>>> requesApitMap = new HashMap<>();
        for (String sheetRequest : sheetnames) {
            ExcelReader readerRequestApi = ExcelUtil.getReader(FileUtil.file(filePath), sheetRequest);
            List<Map<String, Object>> requesApitList = readerRequestApi.readAll();
            requesApitMap.put(sheetRequest, requesApitList);
            readerRequestApi.close();
        }
        if (mapList.size() == 0 || assertList.size() == 0 || requestList.size() == 0) {
            throw new RuntimeException("模板格式错误:案例信息、断言信息、请求信息等sheet存在为空的sheet页,请检查");
        }
        reader.close();
        readerAssert.close();
        readerRequest.close();
        CaseInformationEntity caseInformationEntity = new CaseInformationEntity();
        caseInformationEntity.setCaseInformation(mapList);
        caseInformationEntity.setAssertionMessage(assertList);
        caseInformationEntity.setRequestInforMation(requestList);
        caseInformationEntity.setRequestApiParams(requesApitMap);
        logger.info("读取文件信息且组合参数为：{}", caseInformationEntity);
        return caseInformationEntity;

    }


    /**
     * 校验模板数据
     *
     * @param filePath 文件路径
     * @return 模板是否符合规范
     */
    public List<String> ReadTemplateExcelCheck(String filePath) {
        ExcelReader reader = ExcelUtil.getReader(FileUtil.file(filePath));
        List<String> sheetNames = reader.getSheetNames();
        //0.判断模板是否为空，且必须大于等于4,且模板名称规范
        if (sheetNames.size() >= 4
                && sheetNames.contains(SheetNameType.CASEINFORMATION.getSheetName())
                && sheetNames.contains(SheetNameType.ASSERTIONMESSAGE.getSheetName())
                && sheetNames.contains(SheetNameType.REQUESTINFORMATION.getSheetName())
        ) {
            ArrayList<String> sheetNamesRequest = new ArrayList<>();
            sheetNamesRequest.add(SheetNameType.CASEINFORMATION.getSheetName());
            sheetNamesRequest.add(SheetNameType.ASSERTIONMESSAGE.getSheetName());
            sheetNamesRequest.add(SheetNameType.REQUESTINFORMATION.getSheetName());
            sheetNames.removeAll(sheetNamesRequest);
            for (String sheetName : sheetNames) {
                if (!sheetName.contains(SheetNameType.REQUEST.getSheetName())) {
                    throw new RuntimeException("模板格式错误:sheet页不包含请求或者有其他名称的sheet页");
                }
            }
        } else {
            throw new RuntimeException("模板格式错误:sheet页不包含案例信息、断言信息、请求信息、请求等");
        }
        //1.校验案例信息是否包含小场景名称,和TestCaseId两列
        ExcelReader readerCase = ExcelUtil.getReader(FileUtil.file(filePath), SheetNameType.CASEINFORMATION.getSheetName());
        List<String> objectList = readerCase.readRow(0).stream().map(Object::toString).collect(Collectors.toList());
        if (!(objectList.size() == 2
                && objectList.contains(CollNameType.SAMLLSCENE.getCollName())
                && objectList.contains(CollNameType.TESTCASEID.getCollName()))
        ) {
            throw new RuntimeException("模板格式错误:案例信息sheet页不包含【小场景名称】【TestCaseId】或者有其他名称的列或者第一列不为标题");
        }
        //2.断言信息是否包含断言编号和断言1、断言2等等
        ExcelReader readerAssert = ExcelUtil.getReader(FileUtil.file(filePath), SheetNameType.ASSERTIONMESSAGE.getSheetName());
        List<String> asserttList = readerAssert.readRow(0).stream().map(Object::toString).collect(Collectors.toList());
        if (asserttList.contains(CollNameType.ASSERTIONNUMBER.getCollName())
        ) {
            asserttList.remove(CollNameType.ASSERTIONNUMBER.getCollName());
            for (String assertT : asserttList) {
                if (!assertT.contains(CollNameType.ASSERTION.getCollName())) {
                    throw new RuntimeException("模板格式错误:断言信息sheet页不包含【断言编号】【断言1】【断言2】或者有其他名称的列或者第一列不为标题");
                }
            }
        } else {
            throw new RuntimeException("模板格式错误:断言信息sheet页不包含【断言编号】【断言1】【断言2】或者有其他名称的列或者第一列不为标题");
        }
        //3.请求信息是否包含TestCaseId,和请求信息、断言、请求参数四列
        ExcelReader readerRequest = ExcelUtil.getReader(FileUtil.file(filePath), SheetNameType.REQUESTINFORMATION.getSheetName());
        List<String> requesttList = readerRequest.readRow(0).stream().map(Object::toString).collect(Collectors.toList());
        if (!(requesttList.size() == 4
                && requesttList.contains(CollNameType.TESTCASEID.getCollName())
                && requesttList.contains(CollNameType.ASSERTION.getCollName())
                && requesttList.contains(CollNameType.REQUESTINFORMATION.getCollName())
                && requesttList.contains(CollNameType.REQUESTPARAMETERS.getCollName()))
        ) {
            throw new RuntimeException("模板格式错误:断言信息sheet页不包含【TestCaseId】【请求信息】【断言】【请求参数】或者有其他名称的列或者第一列不为标题");
        }
        //4.校验【请求1】【请求2】等等 参数名称 参数值两列
        for (String sheetName : sheetNames) {
            ExcelReader readerRequestValue = ExcelUtil.getReader(FileUtil.file(filePath), sheetName);
            List<String> requestValuetList = readerRequestValue.readRow(0).stream().map(Object::toString).collect(Collectors.toList());
            if (!(requestValuetList.size() == 2
                    && requestValuetList.contains(CollNameType.PARAMETERSNAME.getCollName())
                    && requestValuetList.contains(CollNameType.PARAMETERSVALUE.getCollName()))
            ) {
                String msg = String.format("模板格式错误:%s sheet页不包含【参数名称】【参数值】或者有其他名称的列或者第一列不为标题", sheetName);
                throw new RuntimeException(msg);
            }
            readerRequestValue.close();
        }
        reader.close();
        readerCase.close();
        readerAssert.close();
        readerRequest.close();
        return sheetNames;
    }


    /**
     * 从类文件路径获取对应的Excel文件路径
     *
     * @param classFilePath 类文件路径
     * @param className     类名
     * @return Excel文件路径
     */
    public  String getExcelPathFromClassPath(String classFilePath, String className) {
        try {
            if (classFilePath == null || className == null) {
                return null;
            }

            // 移除 "file:/" 前缀
            String path = classFilePath.replace("file:/", "");

            // 替换类文件后缀为Excel后缀
            String classSuffix = "/" + className;
            String excelSuffix ="/" + className.replace(".class","Tc.xlsx");

            // 替换tc目录为http目录
            path = path.replace("/tc/", "/http/");

            // 替换文件后缀
            path = path.replace(classSuffix, excelSuffix);

            // 解码URL
            return URLDecoder.decode(path, StandardCharsets.UTF_8.name());

        } catch (Exception e) {
            System.err.println("获取Excel路径失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

}
